package com.github.hgkmail.hello.interview.multithread;

import java.util.concurrent.*;

//Java后来发现以 thread 为主体去开发多线程应用容易出错，改成以 task 为主体去用多线程
//1.开发人员不直接创建线程，而是使用[工厂方法]创建线程池，Executors工厂类提供4种常见的线程池：Fixed、Single、Scheduled、Cached，
// 线程池基础是[ThreadPoolExecutor]，定时任务线程池ScheduledThreadPoolExecutor是ThreadPoolExecutor + delay。
//2.开发人员向线程池提交任务Callable<T> task(相比runnable可以返回一个值)，任务内部可以通过Thread.currentThread()来获取当前线程
//fork/join比较少用，涉及任务分解(fork启动子任务 join等待子任务)、工作窃取算法(从队尾偷任务)等，了解即可。
public class TestTask {
    int sum=0;

    //线程池基本是使用 [fixed] 模式
    //corePoolSize 基本线程数，没有任务也要保持这个数
    //corePoolSize = maxPoolSize = n
    //keepAliveTime=0 线程永久存活
    //隐患：任务队列没有限制容量capacity，可能导致OOM
    void testFixed() throws InterruptedException {
        int poolSize=5;
        int taskNum=100;
        //倒数等待锁
        CountDownLatch taskDone=new CountDownLatch(taskNum);
        //线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(poolSize);
        for (int i = 1; i <= taskNum; i++) {
            threadPool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                    sum+=1;
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    taskDone.countDown();
                }
            });
        }
        //等待任务全部完成
        taskDone.await();
        System.out.println(sum);

        //必须关闭线程池，不然主线程不会退出。。
        threadPool.shutdown(); //关闭线程池
        threadPool.awaitTermination(0, TimeUnit.MILLISECONDS); //等线程池真正关闭
    }

    //newCachedThreadPool有隐患，尽量不要使用，快速提交100个任务居然创建了100个线程。。。
    //core=0，max=int最大值
    //keepAliveTime=60秒
    void testCached() {
        ExecutorService threadPool = Executors.newCachedThreadPool();

    }

    //只有一个线程的线程池。。。
    //注意方法名字，是Executor，而不是Pool
    void testSingle() {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();

    }

    //Saturn单机版
    void testScheduled() {
        int poolSize=3;
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(poolSize);
        //schedule方法只在delay后执行一次。。
        //定时delay使用 scheduleWithFixedDelay 方法
        scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                System.out.println("one second past: "+System.currentTimeMillis()/1000);
            }
        }, 0, 1, TimeUnit.SECONDS);
    }

    public static void main(String[] args) {
        TestTask test=new TestTask();
//        try {
//            test.testFixed();
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        test.testScheduled();
    }
}
